/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2022-01-20 11:56:35
 * @LastEditors: zhanggq
 * @LastEditTime: 2023-11-27 14:10:05
 * @Description: 文件实现描述
 */
#include "CLogger.h"
#include "CloudEdgeManager.h"
#include "JsonManager.h"
#include "common.h"


#define CLOUD_TO_EDGE_DEV_TOPIC(sn)  "c2d/"+sn+"/command/default/v1"


CloudEdgeManager::CloudEdgeManager(std::shared_ptr<CConfigManager> cm, std::shared_ptr<TaskManager> tm, 
    std::shared_ptr<CMosquittoManager> mm, std::shared_ptr<DataCenterManager> dcm){
    c_cm = cm;
    c_tm = tm;
    c_local_mm = mm;
    c_mm = std::make_shared<CMosquittoManager>();
    c_sn = get_sn();
    c_dcm = dcm;

    c_actived = false;
    memset(c_host, 0, sizeof(c_host));
    memset(c_username, 0, sizeof(c_username));
    memset(c_password, 0, sizeof(c_password));

}

CloudEdgeManager::~CloudEdgeManager(){
}

int CloudEdgeManager::subscribe_topics(){
    std::string topic = CLOUD_TO_EDGE_DEV_TOPIC(c_sn);
    int ret =  c_mm->subscribe(topic.c_str());
    if(MOSQ_ERR_SUCCESS != ret){
        return MOSQ_ERR_NOT_SUPPORTED;
    }
    return MOSQ_ERR_SUCCESS;
}
int CloudEdgeManager::handle_message(void *data, int data_len){
    struct mosquitto_message *msg = (struct mosquitto_message *)data;
    std::string topic = CLOUD_TO_EDGE_DEV_TOPIC(c_sn);
    std::string payload = (char *)msg->payload;
    if(0 == strcmp(msg->topic, topic.c_str())){
        JsonManager::getInstance().parse(c_cm, c_tm, c_local_mm,c_dcm, payload);
    }
    return 0;
}
//MQTT回调函数
int CloudEdgeManager::cloud_callback(CALLBACK_TYPE cb_type, void *data, int data_len, int result, void *arg){
    CLogger::getInstance()->log_d("云边通信: 回调方法(%d)", cb_type);
    if(NULL == data){
        return -1;
    }
    try{
        CloudEdgeManager *cem = NULL;
        if(NULL != arg){
            cem = (CloudEdgeManager *)arg;
        }
        switch(cb_type){
            case CALLBACK_TYPE_CONNECTED:
                cem->c_mm->c_actived = true;
                cem->c_actived = true;
                cem->subscribe_topics();
                CLogger::getInstance()->LOG_I("CloudEdgeManager:connected to cloud broker[%s:%d].",cem->c_host,cem->c_port);
            break;
            case CALLBACK_TYPE_MESSAGE:
                cem->handle_message(data, data_len);
            break;
            case CALLBACK_TYPE_PUBLISH:
            break;
            case CALLBACK_TYPE_SUBSCRIBE:
            break;
            case CALLBACK_TYPE_UNSUBSCRIBE:
            break;
            case CALLBACK_TYPE_LOG:
            break;
            case CALLBACK_TYPE_DISCONNECTED:
                cem->c_mm->c_actived = false;
                cem->c_actived = false;
                CLogger::getInstance()->LOG_I("CloudEdgeManager:disconnected from broker.");
            break;
            default:
            break;
        }
    } catch(...){

    }
    CLogger::getInstance()->log_d("%s{%d}", (char *)data, result);
    return result;
}

int CloudEdgeManager::connectBroker(const char *host, int port, const char *username, const char *password, int keepalive)
{
    if ((nullptr ==host) || (nullptr ==username) || (nullptr ==password))  {
        return -1;
    }

    c_port = port;
    c_keepalive = keepalive;
    if (0 > c_keepalive){
        c_keepalive = 0;
    }

    strncpy(c_host, host, sizeof(c_host) -1);
    strncpy(c_username, username, sizeof(c_username) -1);
    strncpy(c_password, password, sizeof(c_password) -1);

    pthread_create(&c_conn_thread, NULL, conn_thread, this);
}

void* CloudEdgeManager::conn_thread(void *arg)
{
    pthread_detach(pthread_self());
    if (nullptr == arg){
        return nullptr;
    }

    CloudEdgeManager* cem = (CloudEdgeManager*)arg;
    while (true)
    {
        if (!cem->c_actived ){
            cem->connect();
        }
        else{
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    }

    return nullptr;
}

int CloudEdgeManager::connect(){

    if(MOSQ_ERR_SUCCESS == c_mm->init(this, cloud_callback)){
        int ret = c_mm->connect((const char*)c_host, c_port, (const char*)c_username,(const char*)c_password, c_keepalive);
        if(MOSQ_ERR_SUCCESS == ret){
            c_mm->start();
        }else{
            c_mm->stop();
            return MOSQ_ERR_CONN_LOST;
        }
    }
    return MOSQ_ERR_SUCCESS;
}

std::string CloudEdgeManager::get_sn(){
    char buf[128] = {0};
    if(1 > get_dev_sn(buf, sizeof(buf))){
        return "T11111111111111111111111";
    }
    return buf;
}
